package admin

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"io"
	"myai/core"
	"myai/core/types"
	"myai/handler"
	"myai/service/oss"
	"myai/store/model"
	"myai/store/model/req"
	"myai/store/vo"
	"myai/utils"
	"myai/utils/resp"
	"net/http"
	"time"
)

type UploadHandler struct {
	handler.BaseHandler
	uploaderManager *oss.UploaderManager
}

func NewUploadHandler(app *core.AppServer, db *gorm.DB, manager *oss.UploaderManager) *UploadHandler {
	return &UploadHandler{BaseHandler: handler.BaseHandler{App: app, DB: db}, uploaderManager: manager}
}

// Upload godoc
// @Summary      上传文件
// @Description  上传文件
// @Tags         后台管理-文件管理
// @Accept       json
// @Produce      json
// @Param 		 file formData  file true "上传的文件"
// @Success      200  {object}  types.BizVo{data=model.File}
// @Router       /api/admin/file/upload [post]
// @Security AdminApiKeyAuth
func (h *UploadHandler) Upload(c *gin.Context) {
	// 上传文件
	file, err := h.uploaderManager.GetUploadHandler().PutFile(c, "file")
	if err != nil {
		resp.ERROR(c, "上传文件失败："+err.Error())
		return
	}
	userId := 0
	// 保存文件信息
	res := h.DB.Create(&model.File{
		UserId:    userId,
		Name:      file.Name,
		ObjKey:    file.ObjKey,
		URL:       file.URL,
		Ext:       file.Ext,
		Size:      file.Size,
		CreatedAt: time.Time{},
	})
	if res.Error != nil || res.RowsAffected == 0 {
		resp.ERROR(c, "上传文件信息保存到数据库出错："+res.Error.Error())
		return
	}
	resp.SUCCESS(c, file)
}

// List godoc
// @Summary      查询文件列表
// @Description  查询文件列表
// @Tags         后台管理-文件管理
// @Accept       json
// @Produce      json
// @Param        req   body     req.FileListReq  true  "文件查询条件"
// @Success      200  {object}  types.BizVo{data=vo.Page}
// @Router       /api/admin/file/list [post]
// @Security AdminApiKeyAuth
func (h *UploadHandler) List(c *gin.Context) {
	var data req.FileListReq
	if err := c.ShouldBindJSON(&data); err != nil {
		resp.ERROR(c, types.InvalidArgs)
		return
	}

	var items []model.File
	var files = make([]vo.File, 0)
	session := h.DB.Session(&gorm.Session{})
	// userId := h.GetLoginUserId(c)
	// 去掉根据用户查询文件，因为我们管理员在后台查看用户会话和聊天消息的时候，如果根据用户Id进行查询文件就会查找不到文件
	// session = session.Where("user_id = ?", userId)
	if len(data.Urls) > 0 {
		session = session.Where("url IN ?", data.Urls)
	}
	// 总计总数
	var total int64
	session.Model(&model.File{}).Count(&total)

	if data.Page > 0 && data.PageSize > 0 {
		offset := (data.Page - 1) * data.PageSize
		session = session.Offset(offset).Limit(data.PageSize)
	}

	err := session.Order("id desc").Find(&items).Error
	if err != nil {
		resp.ERROR(c, "查询文件列表出错："+err.Error())
		return
	}

	for _, v := range items {
		var file vo.File
		err = utils.CopyObject(v, &file)
		if err != nil {
			log.Errorf("拷贝数据出错：" + err.Error())
			continue
		}
		file.CreatedAt = v.CreatedAt.Unix()
		files = append(files, file)
	}
	resp.SUCCESS(c, vo.NewPage(total, data.Page, data.PageSize, files))
}

// Remove godoc
// @Summary      删除文件
// @Description  删除文件
// @Tags         后台管理-文件管理
// @Accept       json
// @Produce      json
// @Param        id   query     int  true  "文件Id"
// @Success      200  {object}  types.BizVo{}
// @Router       /api/admin/file/remove [get]
// @Security AdminApiKeyAuth
func (h *UploadHandler) Remove(c *gin.Context) {
	userId := h.GetLoginUserId(c)
	id := h.GetInt(c, "id", 0)
	var file model.File
	tx := h.DB.Where("user_id = ? and id = ?", userId, id).First(&file)
	if tx.Error != nil || file.Id == 0 {
		resp.ERROR(c, "文件不存在："+tx.Error.Error())
		return
	}
	// 删除数据库文件记录
	tx = h.DB.Model(&model.File{}).Delete("id = ?", file.Id)
	if tx.Error != nil || tx.RowsAffected == 0 {
		resp.ERROR(c, "删除文件信息数据库出错："+tx.Error.Error())
		return
	}
	// 删除文件
	objectKey := file.ObjKey
	if objectKey == "" {
		objectKey = file.URL
	}
	_ = h.uploaderManager.GetUploadHandler().Delete(objectKey)
	resp.SUCCESS(c)
}

// Download godoc
// @Summary      使用给定的链接进行下载文件
// @Description  使用给定的链接进行下载文件
// @Tags         后台管理-文件管理
// @Accept       json
// @Produce      json
// @Param        url   query     string  true  "文件地址"
// @Success 200 {file} file "文件流"
// @Router       /api/admin/file/download [get]
// @Security AdminApiKeyAuth
func (h *UploadHandler) Download(c *gin.Context) {
	fileUrl := h.GetTrim(c, "url")
	// 使用http工具下载文件
	if fileUrl == "" {
		resp.ERROR(c, types.InvalidArgs)
		return
	}
	// 下载文件
	r, err := http.Get(fileUrl)
	if err != nil {
		resp.ERROR(c, "下载文件时出现错误："+err.Error())
		return
	}
	defer r.Body.Close()
	if r.StatusCode != http.StatusOK {
		resp.ERROR(c, fmt.Sprintf("下载文件返回状态码不正确：%s", r.Status))
		return
	}
	// 设置状态码
	c.Status(http.StatusOK)
	// 将下载的文件内容写入响应
	_, _ = io.Copy(c.Writer, r.Body)
}
